package modelo;

import java.awt.Color;
import java.awt.Graphics;

import modelo.Reta;
import modelo.FiguraGeometrica;
import modelo.Ponto;

public class Reta extends FiguraGeometrica{

	private Ponto p1;
	private Ponto p2;
	private float m;
	protected int b;

	public Reta(Ponto p1, Ponto p2){
		this(Color.BLACK, p1, p2);		
	}

	public Reta(Color c, Ponto p1, Ponto p2){
		super(c);
		this.p1 = p1;
		this.p2 = p2;

		// Calcula os valores de m e b.
		if (p1.getX() == p2.getX()) {
			this.m = Float.POSITIVE_INFINITY;
			b = (int) Float.POSITIVE_INFINITY;
		} else {
			float x1 = p1.getX();
			float x2 = p2.getX();
			float y1 = p1.getY();
			float y2 = p2.getY();
			this.m = (y1-y2) / (x1-x2);
			this.b = (int) (-m * p1.getX() + p1.getY());
		}

		desenhaMetodoDdaInteiro();
	}

	private void retaVertical() {
		if (p1.getY() < p2.getY()) {
			for (int i = p1.getY(); i <= p2.getY(); i++) {
				this.getPontos().add(new Ponto(p1.getX(), i));
			}
		} else {
			for (int i = p2.getY(); i <= p1.getY(); i++) {
				this.getPontos().add(new Ponto(p1.getX(), i));
			}
		}
	}

	private void retaHorizontal() {
		if (p1.getX() < p2.getX()) {
			for (int i = p1.getX(); i <= p2.getX(); i++) {
				this.getPontos().add(new Ponto(i, p1.getY()));
			}
		} else {
			for (int i = p2.getX(); i <= p1.getX(); i++) {
				this.getPontos().add(new Ponto(i, p1.getY()));
			}
		}
	}

	private void retaDiagonalPositiva() {
		int r = 0;
		if (p1.getX() < p2.getX()) {
			for (int i = p1.getX(); i < p2.getX(); i++) {
				this.getPontos().add(new Ponto(p1.getX() + r, p1.getY() + r));
				r++;
			}
		} else {
			for (int i = p2.getX(); i < p1.getX(); i++) {
				this.getPontos().add(new Ponto(p2.getX() + r, p2.getY() + r));
				r++;
			}
		}
	}

	private void retaDiagonalNegativa() {
		int r = 0;
		if (p1.getX() < p2.getX()) {
			for (int i = p1.getX(); i < p2.getX(); i++) {
				this.getPontos().add(new Ponto(p1.getX() + r, p1.getY() - r));
				r++;
			}
		} else {
			for (int i = p2.getX(); i < p1.getX(); i++) {
				this.getPontos().add(new Ponto(p2.getX() + r, p2.getY() - r));
				r++;
			}
		}
	}
	private void retaInclinada(){
		int erro, deltax, deltay, r, x, y;

		Ponto p1, p2;

		p1 = new Ponto(this.p1.getX(), this.p1.getY());
		p2 = new Ponto(this.p2.getX(), this.p2.getY());

		if(p1.getY()>p2.getY()){
			Ponto p_aux = new Ponto(p1.getX(), p1.getY());
			p1.setX(p2.getX());
			p1.setY(p2.getY());
			p2.setX(p_aux.getX());
			p2.setY(p_aux.getY());
		}

		erro = 0;
		deltax = p2.getX() - p1.getX();
		deltay = p2.getY() - p1.getY();
		x = p1.getX();
		y = p1.getY();

		this.getPontos().add(new Ponto(x, y));

		if(deltax>=0){
			if(Math.abs(deltax)>=Math.abs(deltay)){ //Caso 1
				for(r=1;r<Math.abs(deltax);r++){
					if(erro<0){
						x++;
						this.getPontos().add(new Ponto(x, y));
						erro += deltay;
					}else{
						x++;
						y++;
						this.getPontos().add(new Ponto(x, y));
						erro += deltay - deltax;
					}
				}
			}else{ //Caso 2
				for(r=1;r<Math.abs(deltay);r++){
					if(erro<0){
						x++;
						y++;
						this.getPontos().add(new Ponto(x, y));
						erro += deltay - deltax;
					}else{
						y++;
						this.getPontos().add(new Ponto(x, y));
						erro -= deltax;
					}
				}
			}
		}else{
			if(Math.abs(deltax)>=Math.abs(deltay)){ //Caso 3
				for(r=1;r<Math.abs(deltax);r++){
					if(erro<0){
						x--;
						this.getPontos().add(new Ponto(x, y));
						erro += deltay;
					}else{
						x--;
						y++;
						this.getPontos().add(new Ponto(x, y));
						erro += deltay + deltax;
					}
				}
			}else{ //Caso 4
				for(r=1;r<Math.abs(deltay);r++){
					if(erro<0){
						x--;
						y++;
						this.getPontos().add(new Ponto(x, y));
						erro += deltay + deltax;
					}else{
						y++;
						this.getPontos().add(new Ponto(x, y));
						erro += deltax;
					}
				}
			}
		}

		this.getPontos().add(new Ponto(p1.getX(), p1.getY()));
		this.getPontos().add(new Ponto(p2.getX(), p2.getY()));
	}


	private FiguraGeometrica cruzamento(Reta r) {
		int xIntersecao, yIntersecao;

		if (r.getM() != m) {
			if (m == Float.POSITIVE_INFINITY) {
				xIntersecao = p1.getX();
				yIntersecao = (int) (r.getM() * xIntersecao + r.getB());
			} else if (r.getM() == Float.POSITIVE_INFINITY) {
				xIntersecao = r.getP1().getX();
				yIntersecao = (int) (m * xIntersecao + b);
			} else {
				xIntersecao = (int) ((r.getB() - b) / (m - r.getM()));
				yIntersecao = (int) ((r.getB() * m - b * r.getM()) / (m - r
						.getM()));
			}
			return new Ponto(Color.RED, xIntersecao, yIntersecao);
		} else {
			if (p1.isInPoint(r.getP1())) {
				return this;
			} else {
				return null;
			}
		}
	}

	public void desenhaMetodoDdaInteiro() {

		int deltaX = p2.getX() - p1.getX();
		int deltaY = p2.getY() - p1.getY();

		if (deltaX == 0) {
			retaVertical();
			return;
		}

		if (deltaY == 0) {
			retaHorizontal();
			return;
		}

		if (deltaX == deltaY) {
			retaDiagonalPositiva();
			return;
		}

		if (deltaX == -deltaY) {
			retaDiagonalNegativa();
			return;
		}

		retaInclinada();
	}

	public Ponto getP1() {
		return p1;
	}

	public void setP1(Ponto p1) {
		this.p1 = p1;
	}

	public Ponto getP2() {
		return p2;
	}

	public void setP2(Ponto p2) {
		this.p2 = p2;
	}

	public float getM() {
		return m;
	}

	public void setM(float m) {
		this.m = m;
	}

	public int getB() {
		return b;
	}

	public void setB(int b) {
		this.b = b;
	}

	public float getMInverse(){
		if(m==Float.POSITIVE_INFINITY){
			return 0;
		}if(m==0){
			return Float.POSITIVE_INFINITY;
		}
		return 1/m;
	}

	public boolean isp1Equal(Ponto v) {
		if (v.getX() == p1.getX() && v.getY() == p1.getY()) {
			return true;
		}
		return false;
	}

	public boolean isp2Equal(Ponto v) {
		if (v.getX() == p2.getX() && v.getY() == p2.getY()) {
			return true;
		}
		return false;
	}

	public boolean isEqual(Reta A) {
		if (isp1Equal(A.getP1()) && isp2Equal(A.getP2()))
			return true;
		if (isp1Equal(A.getP2()) && isp2Equal(A.getP1()))
			return true;
		return false;
	}
}
